package com.hicorp.segment.security.services;

import com.hicorp.segment.mapper.*;
import com.hicorp.segment.pojo.bo.UserForSecurityBO;
import com.hicorp.segment.pojo.po.BackendApi;
import com.hicorp.segment.pojo.po.Menu;
import com.hicorp.segment.pojo.po.User;
import com.hicorp.segment.security.exception.RoleNotFoundException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 实现 UserDetailsService 接口，重写验证机制。
 *
 * @author 万一
 */
@Service
public class UserDetailServiceImpl implements UserDetailsService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private OperationMapper operationMapper;

    @Resource
    private BackendApiMapper backendApiMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        // 按前端传来的用户名查询用户.
        User user = userMapper.findByUserName(s);

        // 如果查询到的User为空.
        if (user == null) throw new UsernameNotFoundException("admin: " + s + "do not exist!");

        // 断言 查询到的 User存在, 但无账号或密码的情况.
        Assert.isTrue(user.getUsername() != null && !"".equals(user.getUsername()) && user.getPassword() != null, "Cannot pass null or empty values to constructor");

        // 所有可访问的页面
        List<Menu> menuList;

        // 所有的可访问的后台接口
        List<BackendApi> backendApiList;

        // spring security 权限验证List
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();

        // 开发人员专用可访问所有的页面 以及 api, 后期部署时需要删除掉.
        if (user.getId() == 1 && user.getUsername().equals("开发人员专用")) {
            menuList = menuMapper.selectAll();
        } else {
//            // 查询该用户所有的角色
//            List<Role> roleList;

            //roleList = roleMapper.selectRoleListByUserId(user.getId());
            //查询用户所有菜单
            menuList = menuMapper.selectMenuListByUserId(user.getId());
            // 当未对用户赋角色时
            if (menuList.size() == 0) throw new RoleNotFoundException("管理员未对该用户授予任何角色!");
            else {
                //查询用户所有权限
                backendApiList=backendApiMapper.selectBackendApiListByUserId(user.getId());
                // 利用流合并去重
                menuList = Stream.of(menuList)
                        .flatMap(Collection::stream)
                        .distinct()
                        .collect(Collectors.toList());
                backendApiList = Stream.of(backendApiList)
                        .flatMap(Collection::stream)
                        .distinct()
                        .collect(Collectors.toList());
            }

            // 当 grantedAuthorities 无数据时
            if (CollectionUtils.isEmpty(grantedAuthorities)) {
                backendApiList.forEach(backendApi -> {
                    if (backendApi != null ) {
                        // 将权限信息添加到 GrantedAuthority 对象中，在后面权限验证时会使用 GrantedAuthority 对象。
                        // 如无特殊需求，请选择设置了 unique 属性的列！！！
                        GrantedAuthority grantedAuthority = new GrantedAuthorityImpl(backendApi.getApiPath(), backendApi.getMethod());
                        grantedAuthorities.add(grantedAuthority);
                    }
                });
            }
        }

        GrantedAuthority grantedAuthority1 = new GrantedAuthorityImpl("/**", "GET");
        grantedAuthorities.add(grantedAuthority1);
        GrantedAuthority grantedAuthority2 = new GrantedAuthorityImpl("/**", "POST");
        grantedAuthorities.add(grantedAuthority2);
        GrantedAuthority grantedAuthority3 = new GrantedAuthorityImpl("/**", "PUT");
        grantedAuthorities.add(grantedAuthority3);
        GrantedAuthority grantedAuthority4 = new GrantedAuthorityImpl("/**", "DELETE");
        grantedAuthorities.add(grantedAuthority4);

        // 将查询到的菜单转换成树形结构.
        List<Menu> finalMenuList = menuList;
        List<Menu> userMenuList =
                menuList
                        .stream()
                        .filter(menu -> menu.getParentId() != null)
                        .filter(menu -> 1 == menu.getParentId())
                        .peek(menu -> menu.setChildren(getMenuChildren(menu, finalMenuList)))
                        .collect(Collectors.toList());

        return new UserForSecurityBO(user.getUsername(), user.getPassword(), grantedAuthorities, user.getUserNo(), user.getStaffNo(),user.getImgPath(), user.getAuthorityCode(), user.getQueryCode(),userMenuList);
    }

    // 生成树形结构的菜单.
    private List<Menu> getMenuChildren(Menu rootMenu, List<Menu> allMenuList) {
        return allMenuList
                .stream()
                .filter((menu) -> Objects.equals(rootMenu.getId(), menu.getParentId()))
                .collect(Collectors.toList());
    }
}
